
import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;

public class PlayerSkeleton {
        private static String filename;
        public static int selectingIndex = 0;
        public static double start = 0.5, end = 20, stepSize = 1;

        public static int seed = 0;
 public static double    numOfUnitClearedPara,
                                colDifPara,
                                maxHeightOfHolePara,
                                landingHeightPara,
                                sumOfHolesPara,
                                sumOfWellsPara,
                                rowsWithHolesPara,
                                maxWellPara,
                                holeNegMatchPara,
                                holePosMatchPara;
 

 // implement this function to have a working system
 public int pickMove(State s, int[][] legalMoves) {

  // final move for current piece
  int bestMove = 0; 

  // array of all the heuristic values for all possible moves
  double[] hValues = new double[legalMoves.length];

  // predicted number of rows cleared
  int rowsCleared = 0;

  int[][] sField = new int[21][10];

  // start simulating each possible move 
  for(int i = 0; i < legalMoves.length; i++) {

   // duplicate field to simulate the array
   sField = duplicateField(s.getField());

   // duplicate the top[] array
   int[] sTop = duplicateTop(s.getTop());

   int pTurn    = s.getTurnNumber();
   int pOrientation = legalMoves[i][0];
   int pSlot    = legalMoves[i][1];
   int [][] pBottom = s.getpBottom()[s.getNextPiece()];
   int [][] pTop   = s.getpTop()[s.getNextPiece()];
   int [] pHeight   = s.getpHeight()[s.getNextPiece()];
   int [] pWidth   = s.getpWidth()[s.getNextPiece()];

   // get the height of the slot before simulated move
   int sHeight  = simulateHeight(sTop, pBottom, pWidth, pOrientation, pSlot);  

   // check whether current move will result in loss or not, if no then we simulate the move
   if(!checkFieldStatus(sHeight, pHeight, pOrientation, pSlot)) {

    /** 
     * Simulate the move, this method will not clear any full rows yet
     * take note turn number before move is i, so turn number during
     * simulated turn is i+1
     */
    sField = simulateMove(sField, i, sHeight, pTurn, sTop, pBottom, pTop, pWidth, pHeight, pOrientation, pSlot);  

    rowsCleared = this.predictedRowsClear(sField, sHeight, pHeight, sTop, pTop, pWidth, pOrientation, pSlot);

    // we then clear the full rows
    clearRows(sField, sHeight, sTop, pHeight, pOrientation, pSlot);

    // from the new simulated field, we check the heuristic value
    hValues[i] = heuristic(sField, pTurn+1, rowsCleared); 
   }
   // move results in a loss, so heuristic value of move set to negative infinity.
   else {
    hValues[i] = Double.NEGATIVE_INFINITY;
   }
  }

  // after all the heuristic values are determined, find the best move
  double maxHValue = Double.NEGATIVE_INFINITY; 
  for(int i = 0; i < hValues.length; i++) {
   if(hValues[i] >= maxHValue) {
    maxHValue = hValues[i];
    bestMove = i;
   } 
  }
  // System.out.println("best move is "+ bestMove + " for piece number "+ s.getNextPiece());
  // printField(sField); // this will only show the field before the move

  return bestMove;
 }
 
 /**
 simulate the height of the landing piece
 **/
 public int simulateHeight(int[] top, int[][] pBottom, int[] pWidth, int orient, int slot) {

  // height if the first column makes contact
  int height = top[slot] - pBottom[orient][0];

  // for each column beyond the first in the piece
  for(int c = 1; c < pWidth[orient]; c++) {
   height = Math.max(height, top[slot+c] - pBottom[orient][c]);
  } 

  return height;
 }

 /**
  * Clear any full rows in the simulated field
  */
 public void clearRows(int[][] field,int height, int[] top, int[] pHeight,int orient,int slot) {

  // check for full rows - starting at the top
  for(int r = height + pHeight[orient] - 1; r >= height; r--) {

   //check all columns in the row
   boolean full = true;
   for(int c = 0; c < 10; c++) {
    if(field[r][c] == 0) {
     full = false;
     break;
    }
   }

   //if the row was full - remove it and slide above stuff down
   if(full) {

    //for each column
    for(int c = 0; c < 10; c++) {
     //slide down all bricks
     for(int i = r; i < top[c]; i++) {
      field[i][c] = field[i+1][c];
     }

     //lower the top
     top[c]--;
     while(top[c] >= 1 && field[top[c]-1][c] == 0) 
      top[c]--;
    }
   }
  }
 }

 /**
  *  general heuristic method for 1 possible move.
  * will consists of all the heuristics functions in this general method
  */
 public double heuristic(int[][] sField, int turn, int rowsCleared) {

  double heuristic = 0;
  int[] colHoleHeight = new int[10];

  // find all column heights
  int[] colHeights = this.colHeightHeur(sField);

  // max column height. used in f2 to calculate altitude difference
  int maxColHeight = this.maxColHeight(colHeights);

  // min column height. used in f2 to calculate altitude difference
  int minColHeight = this.minColHeight(colHeights), colDif = maxColHeight - minColHeight;

  // estimated landing height of move. refering to f4 in report.
  int landingHeight = this.landingHeight(sField, turn);

  // difference between adjacent column heights
  int[] adjHeightDifference = this.findAdjHeightDifference(colHeights);
  
  //calculate number of total of holes. refering to f5 in report
  int sumOfHoles = this.findNumberOfHoles(sField, colHoleHeight );
  
  //calculate sum of blocks over holes
  int sumOfBlocksOverHoles = this.findSumOfBlocksOverHoles(sField, colHoleHeight);
  
  //finds the height of the topmost hole. refering to f3 in report
  int maxHeightOfHole = this.getHeightOfHighestHole( colHoleHeight );

  //finds the sum of horizontal holes that are connected
  int sumOfConnectingHorizontalHole = this.getNoOfConnectHole(sField, colHeights);//
  
  //find number of rows which has at least one hole. tis is f6 in the report
  int rowsWithHoles = rowsWithHoles(sField);
  
  //number of squares cleared. this is f1 in the report
  int numOfUnitCleared = rowsCleared * 10;
  
  //the value of the well depth for each column
  int[] wellsArray = this.wellsArray(colHeights);
  
  //finds the maximum well depth of all the walls. refering to f8 in report
  int maxWell = this.maxWellDepth(wellsArray);

  //finds the sum of all the well depths. refering to f7 in report
  int sumOfWells = 0;
  for(int i = 0; i < wellsArray.length; i++) {
   sumOfWells += wellsArray[i];
  }

  //finds the number of occupied cells surrounding a hole. refering to f9 in report.
  int pieceNegativeMatch = this.getHoleNegativity(sField);
  
  //finds the number of occupied cells surrounding next piece. refering to f10 in report
  int piecePositiveMatch = this.getNewPieceMatchness(sField, turn);
   
  //weights of each heuristic
  numOfUnitClearedPara    = 1.5;//1.5 with 6 holepos
        colDifPara              = -1.5;
        maxHeightOfHolePara     = -2;
        landingHeightPara  = -12.63;
        sumOfHolesPara   = -13.08;
        sumOfWellsPara   = -11.39;
        rowsWithHolesPara  = -28.2; // 28.2
        maxWellPara   = -5.4;
        holeNegMatchPara  = -12.45;//2.25  << 2.24 gd // 6best
        holePosMatchPara  = 6;    //2.25  << 2.24 gd // 6best
  
  //calculate the sum of all heuristics.
  heuristic =        numOfUnitClearedPara         * numOfUnitCleared +
                                        colDifPara              * colDif +
                                        maxHeightOfHolePara     * maxHeightOfHole +
                                        landingHeightPara       * landingHeight +
     sumOfHolesPara          * sumOfHoles +
     sumOfWellsPara          * sumOfWells +
     rowsWithHolesPara       * rowsWithHoles +
     maxWellPara             * maxWell +
     holeNegMatchPara        * pieceNegativeMatch +
     holePosMatchPara        * piecePositiveMatch;
  
  return heuristic; 
 }

 /**
  * Helper methods to print field and other data structures
  */ 
 public void printColHeights(int[] colHeights) {
  System.out.println("Printing col heights in process");
  for(int i = 0; i < colHeights.length; i++) {
   System.out.print("[" + colHeights[i] + "]");
  }
 }

 public void printField(int[][] field) {
  System.out.println("Printing field in process");
  for(int i = field.length - 1; i >= 0; i--) {
   System.out.print("row " + i);
   for(int j = 0;j < field[i].length; j++) {
    System.out.print("["+field[i][j]+"]");
   }
   System.out.println();
  }
 }

 /**
  * Bonus heuristics for number of rows cleared in simulated field
  */
 public int predictedRowsClear(int[][] field, int height,int[] pHeight, int[] top, int[][] pTop, int[] pWidth, int orient, int slot) {

  int rowsCleared = 0;
  int[][] dField = duplicateField(field);

  Boolean full = true;

  for(int r = height + pHeight[orient] - 1; r >= height; r--) {

   //check all columns in the row
   full = true;

   for(int c = 0; c < 10; c++) {    
    if(dField[r][c] == 0) {
     full = false;
     break;
    }
   }   
   if(full) 
    rowsCleared++;
  }
  return rowsCleared;
 }

 /**
  * Check if the height is more than or equals to the height which is 21, if yes return lost as true, else returns false
  */
 public boolean checkFieldStatus(int height, int[] pHeight, int orient, int slot) {
  boolean lost = false;

  // check if game ended
  if(height + pHeight[orient] >= 21) {
   lost = true;
  }
  return lost;
 }

 /**
  * This is to simulate the move, but rows that are full will not be cleared in this method.
  * We then check the number of rows possibly cleared for this move in this methods
  * Then we clear the full rows in clearRows method and perfrom the heuristic function.
  */
 public int[][] simulateMove(int[][] field, int move,int height,int turn,int[] top, int[][] pBottom,int[][] pTop, int[] pWidth,int[] pHeight, int orient,int slot){

  turn++;

  for(int i = 0; i < pWidth[orient]; i++) {
   for(int h = height + pBottom[orient][i]; h < height + pTop[orient][i]; h++) {
    field[h][i+slot] = turn;
   }
  }

  for(int c = 0; c < pWidth[orient]; c++) {
   top[slot+c] = height + pTop[orient][c];
  }

  return field;
 }

 /**
  * Duplicated the top array. this array changes with every move, hence the need to duplicate it before simulated move
  */
 public int[] duplicateTop(int[] top) {
  int[] dTop = new int[10];

  for(int i = 0;i < top.length; i++) {
   dTop[i] = top[i];
  }

  return dTop;
 }

 /**
  * Duplicate the field. since the field changes after every move, hence the need to duplicate it before simulated move.
  */
 public int[][] duplicateField(int[][] field) {
  int[][] dField = new int[21][10];

  for(int i = 0; i < field.length; i++) {
   for(int j = 0; j < field[i].length; j++) {
    dField[i][j] = field[i][j];
   }
  }
  return dField;
 }

 /**
  * Finding the minimum of all column heights
  */
 public int minColHeight(int[] colHeights) {
  int minColHeight = 21;

  for(int i = 0; i < colHeights.length; i++) {
   if(colHeights[i] < minColHeight)
    minColHeight = colHeights[i];
  }

  return minColHeight;
 }

 /**
  * Finding the maximum of all column heights
  */
 public int maxColHeight(int[] colHeights) {
  int maxColHeight = 0;

  for(int i = 0; i < colHeights.length; i++) {
   if(colHeights[i] >= maxColHeight)
    maxColHeight = colHeights[i];
  }

  return maxColHeight;
 }

 /**
  * Finding all column heights and return as an array
  */
 public int[] colHeightHeur(int[][] field) {
  int[] colHeight = new int[10];

  for(int i = 0;i < colHeight.length; i++) {
   colHeight[i] = 0;
  }

  for(int j = 0; j < 10; j++) {            // field[i].length is always 10
   for(int i = field.length - 1; i >= 0; i--) {      // field.length is 21
    if(field[i][j] != 0 && colHeight[j] == 0) {
     colHeight[j] = i+1;
     break;
    }
   }
  }
  
  return colHeight;
 }

 /**
  * Find the number of rows with at least one hole
  */
 public int rowsWithHoles(int[][] field) {
  int rows = 0;
  for(int i = 0; i < field.length - 1; i++){
   for(int j = 0; j < field[i].length; j++){
    if(field[i][j] == 0 && field[i+1][j] != 0){
     rows++;
     break;
    }
   }
  }
  return rows;
 }

 /**
  * Finding the estimated landing height. 
  */
 public int landingHeight(int[][] field, int turn) {
  int landingHeight = 0;

  outerloop:{
   for(int i = field.length - 1; i >= 0; i--) {
    for(int j = 0; j < 10; j++) {
     if(field[i][j] == turn) {
      landingHeight = i+1;
      break outerloop;
     }
    }
   }
  }

  return landingHeight;
 }

 /**
  * Find the absolute difference between adjacent column heights
  */
 public int[] findAdjHeightDifference(int[] colHeights ) {
  int[] adjHeightDifference = new int[colHeights.length - 1];

  for (int i = 0; i < adjHeightDifference.length; i++) {
   adjHeightDifference[i] = Math.max(colHeights[i], colHeights[i+1]) - Math.min(colHeights[i], colHeights[i+1]);
  }

  return adjHeightDifference;
 }

 /** 
  * Takes input arg from colHeightHeur()
  * return array of wells  (if value>0 -> depth=value) else (not a well)
  */
 public int[] wellsArray(int[] colHeight) {
  int[] wells = new int[colHeight.length];

  wells[0] = colHeight[1] - colHeight[0];
  wells[colHeight.length - 1] = colHeight[colHeight.length - 2] - colHeight[colHeight.length - 1];

  for(int i = 1; i < colHeight.length - 2; i++) {

   // definition of well: distance between two walls are more than one
   if((colHeight[i-1] - colHeight[i]) > 1 && (colHeight[i+1] - colHeight[i]) > 1) {
    if(colHeight[i+1] > colHeight[i-1])
     wells[i]= colHeight[i-1] - colHeight[i];
    else
     wells[i]= colHeight[i+1] - colHeight[i];
   }
  }
  for(int i=0;i<wells.length;i++) {
   if(wells[i]<0)
    wells[i]=0;
  }

  return wells;
 }

 /**
  * Takes input arg from wellsArray(int[] colHeight)
  * return COL maxWellDepth, if there's no well return 0
  */ 
 public int maxWellDepth(int[] wellsArray) {
  int maxDepth = Integer.MIN_VALUE;

  for(int i = 1; i < wellsArray.length - 1; i++) {
   if(maxDepth < wellsArray[i])
    maxDepth = wellsArray[i];
  }

  if(maxDepth > 1) 
   return maxDepth;
  else 
   return 0;
 }

 /** 
  * Takes input arg from wellsArray(int[] colHeight)
  */ 
 public int numberOfWells(int[] wellsArray) {
  int maxDepth = 0;

  for(int i = 1; i < wellsArray.length-1; i++) {
   if(wellsArray[i] > 1)
    ++maxDepth;
  }

  return maxDepth;
 }

 /**
  * Find number of hole(unoccupied cell) found in field
  */
 public int findNumberOfHoles(int[][] field, int[] holeHeights) {
  int result = 0;

  for(int i = 0 ; i < field[0].length; i++) {
   holeHeights[i] = 0;
   for(int j = 20; j >= 0; j--) {
    if (field[j][i] != 0) {
     for(int k = --j; k >= 0; k--)
      if (field[k][i] == 0) {
       if (holeHeights[i] < k) 
        holeHeights[i] = k;
       result++;
      }

     break;
    }
   }
  }
  return result;
 }

 /**
  * find sums of blocks over holes
  */
 private int findSumOfBlocksOverHoles(int[][] field, int[] holeHeights) {
  int result = 0;

  for(int i = 0; i < field[0].length; i++) {
   for(int j = holeHeights[i] + 1; j < field.length; j++) {
    if (field[j][i] != 0)
     result++;
    else 
     break;
   }
  }      
  return result;
 }

 /**
  * returns the height of the highest hole
  */
 public int getHeightOfHighestHole( int[] holeHeights ) {
  int max = 0;
  for(int i = 0 ; i < holeHeights.length; i++)
   if (max < holeHeights[i] )  
    max = holeHeights[i];
  return max;
 }

 /**
  * find the number of connected holes
  */
 public int getNoOfConnectHole(int[][] field, int[] holeHeights) {
  int result = 0;

  for(int i = 0 ; i < field[0].length - 1; i++) {
   for(int j = holeHeights[i]; j >= 0; j-- ) {
    if (j <= holeHeights[ i+1 ] && field[j][i] == 0 && field[j][i + 1] == 0) {
     result++;
    }
   }
  } 
  return result;
 }

 /**
  * check to get number of occupied blocks surround by hole
         * this heuristic encourages to place a new hole in connective way.
         * @param field -existing field (after new piece is inserting)
  */
 private int getHoleNegativity(int[][] field) {
  int sum = 0;
  boolean check;
  for( int x = 0; x < 10; x ++ ) {
   check = false;
   for( int y = 20; y > 0; y -- )
    if (check && field[y][x] == 0 ) {
     sum += countPieceSuroundingBlock(field, x, y, 0, false);
    }
    else if (!check && field[y][x] > 0)
     check = true;
  }
  return sum;
 }
 /**
         * Check the number of piece surrounding the given location
         * @param field -existing field (after new piece is inserting)
         * @param x - col coordinate
         * @param y - row coordinate
         * @param exclusingPiece - a turn number to be exclude (eg exclude new piece in checking)
         * @param includeBorder - true to include border as a occupied cell
         * @return - a integer, (field no change)
         */
 private int countPieceSuroundingBlock(int[][] field, int x, int y, int exclusingPiece,boolean includeBorder) {
  int sum = 0;

  if ( (x-1 > 0  && field[y][x-1] > 0 && field[y][x-1] != exclusingPiece) || (includeBorder && x -1 < 0) )
                    sum++;
  if ( (x+1 < 10 && field[y][x+1] > 0 && field[y][x+1] != exclusingPiece) || (includeBorder && x + 1 >= 10) )
                    sum++;
  if ( (y-1 > 0  && field[y][x]   > 0 && field[y-1][x] != exclusingPiece) || (includeBorder && y -1 < 0) )
                    sum++;
  if (  y+1 < 20 && field[y][x]   > 0 && field[y+1][x] != exclusingPiece )
                    sum++;
  return sum;
 }
 /**
         * Heuristic function to check how well the new piece has fit into the existing field
         * @param field - existing field (after new piece is inserted)
         * @param turn - current turn number
         * @return 
         */
 private int getNewPieceMatchness(int[][] field, int turn ) {
  int sum = 0;
  for(int y = 0; y < 20; y++)
   for(int x = 0; x < 10; x++)
    if (field[y][x] == turn) {
     sum += countPieceSuroundingBlock(field, x, y, turn,true);
    }
  return sum;
 }

 public static void main(String[] args) {

          // filename = System.currentTimeMillis() + " - result.csv";
            //fileLogger( 0, true); //Write header to new logger file
            PlayerSkeleton p = new PlayerSkeleton();
            //Default values //
            numOfUnitClearedPara    = 1.5;//1.5 with 6 holepos
            colDifPara              = -1.5;
            maxHeightOfHolePara     = -2;
            landingHeightPara  = -12.63;
            sumOfHolesPara   = -13.08;
            sumOfWellsPara   = -11.39;
            rowsWithHolesPara  = -28.2; // 28.2
            maxWellPara   = -5.4;
            holeNegMatchPara  = -12.86;//2.25  << 2.24 gd // 6best
            holePosMatchPara  = 6;    //2.25  << 2.24 gd // 6best
            selectingIndex  = 0;
            start           = 1;
            end             = 1;
            stepSize        = 1;

            //int seed = 0;
            if (args.length == 1) { //input arguments for a range of test cases
                String line =  args[0]+ ",,,";
                String token[] = line.split( ",",4 );
                token[3] = token[3].replace(",", "");
                selectingIndex  = Integer.parseInt(token[0]);
                start           = Double.parseDouble(token[1]);
                end             = Double.parseDouble(token[2]);
                stepSize        = Double.parseDouble(token[3]);
            }
            else if(args.length >= 11) { //Input arguments for specific set of parameters
                    seed = Integer.parseInt(args[0]);
                    numOfUnitClearedPara    = Double.parseDouble(args[1]); // 2.0;
                    colDifPara              = Double.parseDouble(args[2]); // -1.5;
                    maxHeightOfHolePara     = Double.parseDouble(args[3]); // -2;
                    landingHeightPara  = Double.parseDouble(args[4]); // -12.63;
                    sumOfHolesPara   = Double.parseDouble(args[5]); // -13.08;
                    sumOfWellsPara   = Double.parseDouble(args[6]); // -11.39;
                    rowsWithHolesPara  = Double.parseDouble(args[7]); // -24.2;
                    maxWellPara   = Double.parseDouble(args[8]); // -5.4;
                    holeNegMatchPara  = Double.parseDouble(args[9]); // -1;
                    holePosMatchPara  = Double.parseDouble(args[10]); // 1;
            }
            else {
                    //User inputs for test cases
                    //getUserSelection();
            }

            //start testing different set of parameters
            for( double value = start; value <= end; value += stepSize )
            {
                State s = new State();                  //create new game state
                TFrame frame = new TFrame(s);           //create new form
                setParameter( selectingIndex, value );  //reset heruistic parameters
                //s.setRandomSeed(seed);                  //Reset seed no (require set seed for random piece in state
                oneCycle( s , p );                      //process one cycle
                fileLogger( s.getRowsCleared(), false); //log result
                frame.dispose();                        //Dispose old form
                s = null;                               //unsigned old state
            }
            return;
 }
        /**
         * Use to log and save the results for test cases.
         * @param result
         * @param header
         */
        public static void fileLogger( int result, boolean header )
        {
            
            File   actLog = new File( filename );
            FileWriter actLogger;
            try {
                actLogger = new FileWriter(actLog, true); // true to append   ;false to overwrite
                if ( header )
                {
                    actLogger.write( "Result, ," );
                    actLogger.write( "seed" + "," );
                    actLogger.write( "numOfUnitClearedPara" + "," );
                    actLogger.write( "colDifPara" + "," );
                    actLogger.write( "maxHeightOfHolePara" + "," );
                    actLogger.write( "landingHeightPara" + "," );
                    actLogger.write( "sumOfHolesPara" + "," );
                    actLogger.write( "sumOfWellsPara" + "," );
                    actLogger.write( "rowsWithHolesPara" + "," );
                    actLogger.write( "maxWellPara" + "," );
                    actLogger.write( "holeNegMatchPara" + "," );
                    actLogger.write( "holePosMatchPara" + "\n" );
                }
                else
                {
                    System.out.println("You have completed "+ result+" rows.");
                    actLogger.write( result + ",," );
                    actLogger.write( seed + "," );
                    actLogger.write( numOfUnitClearedPara + "," );
                    actLogger.write( colDifPara + "," );
                    actLogger.write( maxHeightOfHolePara + "," );
                    actLogger.write( landingHeightPara + "," );
                    actLogger.write( sumOfHolesPara + "," );
                    actLogger.write( sumOfWellsPara + "," );
                    actLogger.write( rowsWithHolesPara + "," );
                    actLogger.write( maxWellPara + "," );
                    actLogger.write( holeNegMatchPara + "," );
                    actLogger.write( holePosMatchPara + "\n" );
                }
                actLogger.close();

            } catch (IOException ex) {
                
                System.err.print("Fail to open file - " + filename );
                System.exit(-99);
            }
        }
        /**
         * Setting default parameters
         * @param index - index of the testing/varying parameter
         * @param value - value for the parameter
         */

        public static void setParameter(int  index, double value )
        {
            switch( index )
            {
                case 0:         seed = (int)value;                  break;
                case 1:         numOfUnitClearedPara    = value;    break;
                case 2:         colDifPara              = value;    break;
                case 3:         maxHeightOfHolePara     = value;    break;
                case 4:         landingHeightPara  = value;    break;
  case 5:  sumOfHolesPara   = value;    break;
  case 6:  sumOfWellsPara   = value;    break;
  case 7:  rowsWithHolesPara  = value;    break;
  case 8:  maxWellPara   = value;    break;
  case 9:  holeNegMatchPara  = value;    break;
  case 10:  holePosMatchPara  = value;    break;
            }

        }
        /**
         * Standard program cycle
         * @param s , current state
         * @param p , current player
         */
        private static void oneCycle( State s, PlayerSkeleton p )
        {
            //Original code was in main function
            while(!s.hasLost()) {
                    s.makeMove(p.pickMove(s,s.legalMoves()));
                    s.draw();
                    s.drawNext(0,0);
                    
                    try {
                            Thread.sleep(300);
                    } catch (InterruptedException e) {
                            e.printStackTrace();
                    }
            }

        }

        /**
         * Method to get user input for creating test cases
         */
        public static void getUserSelection()
        {
            System.out.print("Please enter a testing parameter index (0-10), min value, max value, step size: [index, min, max, step]\n");
            InputStreamReader converter = new InputStreamReader(System.in);
            BufferedReader in = new BufferedReader(converter);
            try {
                String line = in.readLine() + ",,,";
                String token[] = line.split( ",",4 );
                token[3] = token[3].replace(",", "");

                selectingIndex  = Integer.parseInt(token[0]);
                start           = Double.parseDouble(token[1]);
                end             = Double.parseDouble(token[2]);
                stepSize        = Double.parseDouble(token[3]);

            } catch (IOException ex) {
                Logger.getLogger(PlayerSkeleton.class.getName()).log(Level.SEVERE, null, ex);
            }

        }
}
